#ifndef GTREENODE_H
#define GTREENODE_H

#include <iostream>
#include "gList.h"

using namespace std;

template<class E>
class GTreeNode
{
public:
    GTreeNode(const E& element)
    {
        this->element_ = element;
    }

    ~GTreeNode()
    {
        for (int i = 0; i < this->children_.size(); ++i) {
            GTreeNode<E> *node = this->children_.get(i);
            if(node)
            {
                delete node;
                node = 0;
            }
        }
    }

    int size()
    {
        unsigned size(1);
        for (int i = 0; i < this->children_.size(); i++)
            size += this->children_.get(i)->size();
        return size;
    }

    bool isLeaf()
    {
        return children_.isEmpty();
    }

    void add(const E& element)
    {
        this->children_.add(new GTreeNode<E>(element));
    }

    GTreeNode<E>* search(const E& element)
    {
        GTreeNode<E> *found = 0;
        if(this->element_ == element)
            found = this;
        else
        {
            for(int i = 0; i < this->children_.size(); i++)
            {
                GTreeNode<E> *node = this->children_.get(i);
                found = node && node->element_ == element ? node : node->search(element);
                if(found)
                    break;
            }
        }
        return found;
    }

    void remove(const E& element)
    {
        if(element == this->element_)
            children_.destroy();
        else
        {
            for (int i = 0; i < this->children_.size(); i++)
            {
                GTreeNode<E>* node = this->children_.get(i);
                if(node && node->element_ == element)
                    this->children_.remove(i);
                else
                    node->remove(element);

            }
        }
    }

    void traverse(int level)
    {
        tabulate(level);
        cout << element_ << endl;
        for (int i = 0; i < children_.size(); ++i) {
            GTreeNode<E>* node = this->children_.get(i);
            if(node)
                node->traverse(level+1);
        }
    }

private:
    void tabulate(int level)
    {
        for (int i = 0; i < level; ++i) {
            cout << "\t";
        }
    }

public:
    E element_;
    GList< GTreeNode<E>* > children_;
};

#endif // GTREENODE_H

